/*
  ==============================================================================

   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-11 by Raw Material Software Ltd.

  ------------------------------------------------------------------------------

   JUCE can be redistributed and/or modified under the terms of the GNU General
   Public License (Version 2), as published by the Free Software Foundation.
   A copy of the license is included in the JUCE distribution, or can be found
   online at www.gnu.org/licenses.

   JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  ------------------------------------------------------------------------------

   To release a closed-source product which uses JUCE, commercial licenses are
   available: visit www.rawmaterialsoftware.com/juce for more information.

  ==============================================================================
*/

D3D9Texture::D3D9Texture()
    : D3Dtexture (NULL), width (0), height (0)
{
}

D3D9Texture::~D3D9Texture()
{
    release();
}

bool D3D9Texture::isValidSize (int width, int height)
{
    return isPowerOfTwo (width) && isPowerOfTwo (height);
}

void D3D9Texture::create (const int w, const int h, const void* pixels)
{
    //jassert (D3D9Helpers::isContextActive());

    jassert (isValidSize (w, h)); // Perhaps these dimensions must be a power-of-two?

    width  = w;
    height = h;

	if (D3Dtexture == NULL)
	{
		HRESULT hr = D3D9Helpers::pd3dDevice->CreateTexture( 
			width,
			height,
			1,
			0, 
			D3DFMT_A8R8G8B8,
			D3DPOOL_MANAGED,
			&D3Dtexture,
			NULL );
		jassert(hr == S_OK);
	}

	D3DLOCKED_RECT LockedRect;
	D3Dtexture->LockRect( 0, &LockedRect, NULL, 0 );

	byte* pBase = (byte*)LockedRect.pBits;
	int bytes_per_pixel = 4;
	jassert( bytes_per_pixel * width == LockedRect.Pitch );

	for(int j=0; j<height; j++)
	{
		for(int i=0; i<width; i++)
		{
			byte *Destpixel = pBase + j * LockedRect.Pitch + i * bytes_per_pixel;
			byte *SrcPixel = (byte*)pixels + j * LockedRect.Pitch + i * bytes_per_pixel;
			*((D3DCOLOR*)Destpixel) = 
				D3DCOLOR_ARGB(  ((PixelARGB*)SrcPixel)->getAlpha(), 
								((PixelARGB*)SrcPixel)->getRed(),
								((PixelARGB*)SrcPixel)->getGreen(),
								((PixelARGB*)SrcPixel)->getBlue() );
		}
	}

	D3Dtexture->UnlockRect( 0 );
}

template <class PixelType>
struct Zoomer
{
    static void Zoom (HeapBlock<PixelARGB>& dataCopy, const uint8* srcData, const int lineStride,
                      const int w, const int h, const int textureW, const int textureH)
    {
        dataCopy.malloc (textureW * textureH);

        for (int y = 0; y < h; ++y)
        {
            const PixelType* src = (const PixelType*) srcData;
            PixelARGB* const dst = (PixelARGB*) (dataCopy + textureW * y/*(textureH - 1 - y)*/);

            for (int x = 0; x < w; ++x)
                dst[x].set (src[x]);

            srcData += lineStride;
        }
    }
};

void D3D9Texture::loadImage (const Image& image)
{
    const int imageW = image.getWidth();
    const int imageH = image.getHeight();
    const int textureW = nextPowerOfTwo (imageW);
    const int textureH = nextPowerOfTwo (imageH);

    HeapBlock<PixelARGB> dataCopy;
    Image::BitmapData srcData (image, Image::BitmapData::readOnly);

    switch (srcData.pixelFormat)
    {
        case Image::ARGB:           Zoomer<PixelARGB> ::Zoom (dataCopy, srcData.data, srcData.lineStride, imageW, imageH, textureW, textureH); break;
        case Image::RGB:            Zoomer<PixelRGB>  ::Zoom (dataCopy, srcData.data, srcData.lineStride, imageW, imageH, textureW, textureH); break;
        case Image::SingleChannel:  Zoomer<PixelAlpha>::Zoom (dataCopy, srcData.data, srcData.lineStride, imageW, imageH, textureW, textureH); break;
        default: break;
    }

    create (textureW, textureH, dataCopy);
}

void D3D9Texture::loadARGB (const PixelARGB* pixels, const int w, const int h)
{
    jassert (isValidSize (w, h));
    create (w, h, pixels);
}



void D3D9Texture::release()
{
    if (D3Dtexture != NULL)
    {
        if (D3D9Helpers::isContextActive())
            D3Dtexture->Release();

        D3Dtexture = NULL;
        width = 0;
        height = 0;
    }
}

void D3D9Texture::bind() const
{
	D3D9Helpers::pd3dDevice->SetTexture(0, D3Dtexture);
}

void D3D9Texture::unbind() const
{
	D3D9Helpers::pd3dDevice->SetTexture(0, NULL);
}

#if JUCE_USE_D3D9_FIXED_FUNCTION
void D3D9Texture::draw2D (float x1, float y1,
                            float x2, float y2,
                            float x3, float y3,
                            float x4, float y4,
                            const Colour& colour) const
{

	D3D9Helpers::pd3dDevice->SetTexture(0, D3Dtexture);
    D3D9Helpers::drawQuad2D (x1, y1, x2, y2, x3, y3, x4, y4, colour);
	D3D9Helpers::pd3dDevice->SetTexture(0, NULL);

}

void D3D9Texture::draw3D (float x1, float y1, float z1,
                            float x2, float y2, float z2,
                            float x3, float y3, float z3,
                            float x4, float y4, float z4,
                            const Colour& colour) const
{

	D3D9Helpers::pd3dDevice->SetTexture(0, D3Dtexture);
    D3D9Helpers::drawQuad3D (x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, colour);
	D3D9Helpers::pd3dDevice->SetTexture(0, NULL);

}
#endif
